package com.lcx.plugin.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.lcx.plugin.constants.SqlTemplateConstant;
import com.lcx.plugin.constants.StrConstant;
import com.lcx.plugin.dto.ExcelDbFiledDTO;
import com.lcx.plugin.dto.MySettingsStorageDTO;
import com.lcx.plugin.entity.TypeMapper;
import com.lcx.plugin.enums.DatabaseType;
import com.lcx.plugin.enums.MysqlTypeMatch;
import com.lcx.plugin.service.MySettingsStorageService;
import com.lcx.plugin.service.SqlHandleService;
import com.lcx.plugin.tool.CacheDataUtils;
import com.lcx.plugin.tool.MapSizeUtil;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author daxiong
 * @date 2023/6/21 上午11:09
 */
@Slf4j
public class MySqlHandleServiceImpl implements SqlHandleService {

    /**
     * 自定义的类型映射map
     */
    Map<String, TypeMapper> typeMapperMap;

    public MySqlHandleServiceImpl() {
        // 获取用户自定义的类型映射map
        typeMapperMap = getTypeMapperMap();
    }

    /**
     * 数据缓存工具类
     */
    private final CacheDataUtils cacheDataUtils = CacheDataUtils.getInstance();

    @Override
    public String generateSql(List<ExcelDbFiledDTO> objList, String tableName, String tableNote) {
        StringBuilder sb = new StringBuilder();
        // 拼接列sql
        this.columnSql(objList, sb);
        // 拼接索引sql
        this.indexSql(objList, sb);

        String sql;
        if (cacheDataUtils.isTableExistJump()) {
            // 表存在则跳过
            sql = String.format(SqlTemplateConstant.MYSQL_JUMP_INSERT_TEMPLATE, tableName, sb.toString(), tableNote);
        } else {
            sql = String.format(SqlTemplateConstant.MYSQL_DROP_INSERT_TEMPLATE, tableName, tableName, sb.toString(), tableNote);
        }
        log.info("EasyDB生成sql：" + sql);
        return sql;
    }

    @Override
    public String getDbType() {
        return DatabaseType.MYSQL.getDbType();
    }

    @Override
    public void indexSql(List<ExcelDbFiledDTO> objList, StringBuilder sb) {
        List<String> primaryKeyList = new ArrayList<>();
        Map<String, List<ExcelDbFiledDTO>> normalKeyMap = new HashMap<>(MapSizeUtil.getInitCapacity(objList.size()));
        for (ExcelDbFiledDTO item : objList) {
            if (Objects.equals(item.getMemo(), StrConstant.PRIMARY_KEY_NAME)) {
                // 主键
                primaryKeyList.add(item.getFieldUnderline());
            } else {
                // 非主键
                if (item.isIndex()) {
                    // 该字段是索引字段
                    List<ExcelDbFiledDTO> normalKeyList = normalKeyMap.getOrDefault(item.getIndexName(), new ArrayList<>());
                    normalKeyList.add(item);
                    normalKeyMap.put(item.getIndexName(), normalKeyList);
                }
            }
        }
        // PRIMARY KEY (`id`,`create_time`) USING BTREE,\n
        if (CollUtil.isEmpty(primaryKeyList)) {
            // 如果备注都没有写主键，则默认主键名是id
            primaryKeyList.add("id");
        }
        sb.append("PRIMARY KEY (`").append(String.join("`,`", primaryKeyList)).append("`) USING BTREE,\n");
        String normalKeyStr;
        for (Map.Entry<String, List<ExcelDbFiledDTO>> entry : normalKeyMap.entrySet()) {
            List<ExcelDbFiledDTO> list = entry.getValue();
            ExcelDbFiledDTO excelDbFiledDTO = list.get(0);
            // 索引类型 1：唯一；2：普通
            Integer indexType = excelDbFiledDTO.getIndexType();
            if (Objects.equals(indexType, 1)) {
                normalKeyStr = " UNIQUE KEY ";
            } else {
                normalKeyStr = " KEY ";
            }
            // tenant_id`,`supply_phone
            String collect = list.stream().map(ExcelDbFiledDTO::getFieldUnderline).collect(Collectors.joining("`,`"));
            // UNIQUE KEY `租房下供应商手机号唯一` (`tenant_id`,`supply_phone`) USING BTREE
            sb.append(normalKeyStr).append("`").append(entry.getKey()).append("` (`").append(collect).append("`) USING BTREE ");
            String indexNote = excelDbFiledDTO.getIndexNote();
            // UNIQUE KEY `租房下供应商手机号唯一` (`tenant_id`,`supply_phone`) USING BTREE COMMENT 'tenant supply',
            if (StrUtil.isNotBlank(indexNote)) {
                sb.append(" COMMENT '").append(indexNote).append("',");
            }
            // 如果最后一位不是逗号，则加上逗号
            if (sb.lastIndexOf(StrConstant.SQL_LINE_END) != sb.length() - 1) {
                sb.append(StrConstant.SQL_LINE_END);
            }
            sb.append("\n");
        }
        // 删除最后一个换行和逗号
        sb.delete(sb.length() - 2, sb.length());
        sb.append("\n");
    }

    @Override
    public void columnSql(List<ExcelDbFiledDTO> objList, StringBuilder sb) {
        objList.forEach(item -> this.analysisType(item, sb));
    }

    @Override
    public void analysisType(ExcelDbFiledDTO excelDbFiledDTO, StringBuilder sb) {
        // 根据excelType获取对应的TypeMapper
        TypeMapper typeMapper = typeMapperMap.getOrDefault(
                excelDbFiledDTO.getType().toLowerCase(), new TypeMapper(MysqlTypeMatch.STRING));
        String jdbcType = typeMapper.getJdbcType().toLowerCase();
        // `supply_phone` varchar
        sb.append("`").append(excelDbFiledDTO.getFieldUnderline()).append("` ").append(jdbcType);

        String length = excelDbFiledDTO.getLength();
        if (StrUtil.isBlank(length)) {
            length = StrUtil.isBlank(typeMapper.getDefaultLength()) ? "0" : typeMapper.getDefaultLength();
        }
        // `supply_phone` varchar(20)
        switch (jdbcType) {
            // 某些字段类型要做特殊处理
            case "date":
                // mysql date类型后面不能拼长度
                break;
            case "time":
            case "datetime":
                // mysql DATETIME长度最长为6
                if (Integer.parseInt(length) > 6) {
                    excelDbFiledDTO.setLength("6");
                }
                sb.append("(").append(length).append(") ");
                break;
            default:
                sb.append("(").append(length).append(") ");
                break;
        }

        // `supply_phone` varchar(20) NOT NULL
        if (Objects.equals(excelDbFiledDTO.getMust(), "是")) {
            sb.append(" NOT NULL ");
        }
        // `supply_phone` varchar(20) NOT NULL COMMENT '手机号',
        MySettingsStorageDTO settingsStorage = MySettingsStorageService.getSettingsStorage();
        String comment = "";
        if (settingsStorage.isMergeNameMemo()) {
            if (StrUtil.isNotBlank(excelDbFiledDTO.getMemo())) {
                comment = "(" + excelDbFiledDTO.getMemo() + ")";
            }
            // 需要合并备注
            comment = StrUtil.concat(true, excelDbFiledDTO.getName(), comment);
        } else {
            comment = excelDbFiledDTO.getName();
        }
        if (StrUtil.isNotBlank(comment)) {
            sb.append(" COMMENT '").append(comment).append("',");

        }
        // 如果最后一位不是逗号，则加上逗号
        if (sb.lastIndexOf(StrConstant.SQL_LINE_END) != sb.length() - 1) {
            sb.append(StrConstant.SQL_LINE_END);
        }
        sb.append("\n");
    }

    /**
     * 获取TypeMapper的map
     * key：excelType的小写形式，value：TypeMapper
     *
     * @return java.util.Map<java.lang.String, com.lcx.plugin.entity.TypeMapper>
     * @author daxiong
     * @date 2023/6/23 下午7:48
     */
    private Map<String, TypeMapper> getTypeMapperMap() {
        MySettingsStorageDTO settingsStorage = MySettingsStorageService.getSettingsStorage();
        List<TypeMapper> elementList = settingsStorage.getElementList();
        if (CollUtil.isEmpty(elementList)) {
            // 默认值
            elementList = MysqlTypeMatch.defaultValues();
        }
        return elementList.stream().collect(HashMap::new,
                (map, item) -> map.put(item.getExcelType().toLowerCase(), item), HashMap::putAll);
    }
}
